home *** CD-ROM | disk | FTP | other *** search
/ Aminet 24 / Aminet 24 (1998)(GTI - Schatztruhe)[!][Apr 1998].iso / Aminet / comm / mail / Mutt089src.lha / Mutt-0.89i-AMIGA / src / pattern.c < prev    next >
C/C++ Source or Header  |  1998-01-28  |  19KB  |  856 lines

  1. /*
  2.  * Copyright (C) 1996-8 Michael R. Elkins <me@cs.hmc.edu>
  3.  * 
  4.  *     This program is free software; you can redistribute it and/or modify
  5.  *     it under the terms of the GNU General Public License as published by
  6.  *     the Free Software Foundation; either version 2 of the License, or
  7.  *     (at your option) any later version.
  8.  * 
  9.  *     This program is distributed in the hope that it will be useful,
  10.  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  *     GNU General Public License for more details.
  13.  * 
  14.  *     You should have received a copy of the GNU General Public License
  15.  *     along with this program; if not, write to the Free Software
  16.  *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  */ 
  18.  
  19. #include "mutt.h"
  20. #include "mutt_regex.h"
  21. #include "mapping.h"
  22. #include "keymap.h"
  23. #include "mailbox.h"
  24. #include "state.h"
  25. #include <string.h>
  26. #include <stdlib.h>
  27. #include <ctype.h>
  28. #include <sys/stat.h>
  29. #include <unistd.h>
  30.  
  31. #ifdef _PGPPATH
  32. #include "pgp.h"
  33. #endif
  34.  
  35.  
  36.  
  37.  
  38.  
  39. #define new_pattern() calloc(1, sizeof (pattern_t))
  40.  
  41. typedef struct pattern_t
  42. {
  43.   short op;
  44.   short not;
  45.   time_t notbefore;
  46.   time_t notafter;
  47.   int minmsg;
  48.   int maxmsg;
  49.   struct pattern_t *next;
  50.   struct pattern_t *child; /* arguments to logical op */
  51.   regex_t rx;
  52. } pattern_t;
  53.  
  54. static const char *eat_regexp (pattern_t *pat, const char *s, char *, size_t);
  55. static const char *eat_date (pattern_t *pat, const char *s, char *, size_t);
  56. static const char *eat_range (pattern_t *pat, const char *s, char *, size_t);
  57.  
  58. static int mutt_pattern_exec (struct pattern_t *pat, CONTEXT *ctx, HEADER *h);
  59.  
  60. struct pattern_flags
  61. {
  62.   int tag; /* character used to represent this op */
  63.   int op;  /* operation to perform */
  64.   const char *(*eat_arg) (pattern_t *, const char *, char *, size_t);
  65. }
  66. Flags[] =
  67. {
  68.   { 'A', M_ALL,            NULL },
  69.   { 'D', M_DELETED,        NULL },
  70.   { 'F', M_FLAG,        NULL },
  71.   { 'N', M_NEW,            NULL },
  72.   { 'O', M_OLD,            NULL },
  73.   { 'R', M_READ,        NULL },
  74.   { 'Q', M_REPLIED,        NULL },
  75.   { 'T', M_TAG,            NULL },
  76.   { 'U', M_UNREAD,        NULL },
  77.   { 'b', M_BODY,        eat_regexp },
  78.   { 'c', M_CC,            eat_regexp },
  79.   { 'd', M_DATE,        eat_date },
  80.   { 'e', M_SENDER,        eat_regexp },
  81.   { 'f', M_FROM,        eat_regexp },
  82.   { 'h', M_HEADER,        eat_regexp },
  83.   { 'i', M_ID,            eat_regexp },
  84.   { 'm', M_MESSAGE,        eat_range },
  85.   { 'r', M_DATE_RECEIVED,    eat_regexp },
  86.   { 's', M_SUBJECT,        eat_regexp },
  87.   { 't', M_TO,            eat_regexp },
  88.   { 0 }
  89. };
  90.  
  91.  
  92. static pattern_t *SearchPattern = NULL; /* current search pattern */
  93. static char LastSearch[STRING] = { 0 };    /* last pattern searched for */
  94.  
  95. int mutt_getvaluebychar (char ch, struct mapping_t *table)
  96. {
  97.   int i;
  98.  
  99.   for (i = 0; table[i].name; i++)
  100.   {
  101.     if (ch == table[i].name[0])
  102.       return table[i].value;
  103.   }
  104.  
  105.   return (-1);
  106. }
  107.  
  108. /* if no uppercase letters are given, do a case-insensitive search */
  109. int mutt_which_case (const char *s)
  110. {
  111.   while (*s)
  112.   {
  113.     if (isalpha (*s) && isupper (*s))
  114.       return 0; /* case-sensitive */
  115.     s++;
  116.   }
  117.   return REG_ICASE; /* case-insensitive */
  118. }
  119.  
  120. static int
  121. msg_search (regex_t *rx, char *buf, size_t blen, int is_hdr, int msgno)
  122. {
  123.   char tempfile[_POSIX_PATH_MAX];
  124.   MESSAGE *msg = NULL;
  125.   STATE s;
  126.   struct stat st;
  127.   FILE *fp = NULL;
  128.   long lng;
  129.   int match = 0;
  130.  
  131.   if ((msg = mx_open_message (Context, msgno)) != NULL)
  132.   {
  133.     if (option (OPTTHOROUGHSRC))
  134.     {
  135.       /* decode the header / body */
  136.       memset (&s, 0, sizeof (s));
  137.       s.fpin = msg->fp;
  138.       mutt_mktemp (tempfile);
  139.       if ((s.fpout = safe_fopen (tempfile, "w+")) == NULL)
  140.       {
  141.     mutt_perror (tempfile);
  142.     return (0);
  143.       }
  144.  
  145.       if (is_hdr)
  146.     mutt_copy_header (msg->fp, Context->hdrs[msgno], s.fpout, CH_FROM | CH_DECODE);
  147.       else
  148.       {
  149.     mutt_parse_mime_message (Context->hdrs[msgno]);
  150. #ifdef _PGPPATH
  151.     if (Context->hdrs[msgno]->pgp & PGPENCRYPT && !pgp_valid_passphrase())
  152.     {
  153.       mx_close_message (&msg);
  154.       fclose (fp);
  155.       unlink (tempfile);
  156.       return (0);
  157.     }
  158. #endif
  159.     fseek (msg->fp, Context->hdrs[msgno]->offset, 0);
  160.     mutt_body_handler (Context->hdrs[msgno]->content, &s);
  161.       }
  162.  
  163.       fp = s.fpout;
  164.       fflush (fp);
  165.       fseek (fp, 0, 0);
  166.       fstat (fileno (fp), &st);
  167.       lng = (long) st.st_size;
  168.     }
  169.     else
  170.     {
  171.       /* raw header / body */
  172.       fp = msg->fp;
  173.       if (is_hdr)
  174.       {
  175.     fseek (fp, Context->hdrs[msgno]->offset, 0);
  176.     lng = Context->hdrs[msgno]->content->offset - Context->hdrs[msgno]->offset;
  177.       }
  178.       else
  179.       {
  180.     fseek (msg->fp, Context->hdrs[msgno]->content->offset, 0);
  181.     lng = Context->hdrs[msgno]->content->length;
  182.       }
  183.     }
  184.  
  185.     /* search the file "fp" */
  186.     while (lng > 0)
  187.     {
  188.       if (fgets (buf, blen - 1, fp) == NULL)
  189.     break; /* don't loop forever */
  190.       if (regexec (rx, buf, 0, NULL, 0) == 0)
  191.       {
  192.     match = 1;
  193.     break;
  194.       }
  195.       lng -= strlen (buf);
  196.     }
  197.     
  198.     mx_close_message (&msg);
  199.  
  200.     if (option (OPTTHOROUGHSRC))
  201.     {
  202.       fclose (fp);
  203.       unlink (tempfile);
  204.     }
  205.   }
  206.  
  207.   return match;
  208. }
  209.  
  210. static const char *
  211. eat_regexp (pattern_t *pat, const char *s, char *err, size_t errlen)
  212. {
  213.   char buf[SHORT_STRING];
  214.   char expn[SHORT_STRING];
  215.   const char *ps;
  216.   int r;
  217.  
  218.   ps = mutt_extract_token (buf, sizeof (buf), s, expn, sizeof (expn),
  219.                M_PATTERN | M_COMMENT | M_NULL);
  220.  
  221.   if ((r = REGCOMP (&pat->rx, buf, REG_NEWLINE | REG_NOSUB | mutt_which_case (buf))) != 0)
  222.   {
  223.     regerror (r, &pat->rx, err, errlen);
  224.     regfree (&pat->rx);
  225.     return NULL;
  226.   }
  227.  
  228.   return ps;
  229. }
  230.  
  231. static const char *
  232. eat_range (pattern_t *pat, const char *s, char *err, size_t errlen)
  233. {
  234.   const char *p;
  235.   char *tmp;
  236.  
  237.   if (*s != '-')
  238.   {
  239.     /* range minimum */
  240.     pat->minmsg = strtol (s, &tmp, 0) - 1;
  241.     p = tmp;
  242.   }
  243.   else
  244.   {
  245.     s++;
  246.     p = s;
  247.   }
  248.  
  249.   if (*p != '-')
  250.   {
  251.     pat->maxmsg = pat->minmsg;
  252.     return p;
  253.   }
  254.   p++;
  255.  
  256.   if (isdigit (*p))
  257.   {
  258.     /* range max */
  259.     pat->maxmsg = strtol (p, &tmp, 0) - 1;
  260.     p = tmp;
  261.   }
  262.   else
  263.     pat->maxmsg = Context->msgcount - 1;
  264.  
  265.   return p;
  266. }
  267.  
  268. static const char *
  269. getDate (const char *s, struct tm *t, char *err, size_t errlen)
  270. {
  271.   char *p;
  272.   time_t now = time (NULL);
  273.   struct tm *tm = localtime (&now);
  274.  
  275.   t->tm_mday = strtol (s, &p, 0);
  276.   if (t->tm_mday < 1 || t->tm_mday > 31)
  277.   {
  278.     snprintf (err, errlen, "Invalid day of month: %s", s);
  279.     return NULL;
  280.   }
  281.   if (*p != '/')
  282.   {
  283.     /* fill in today's month and year */
  284.     t->tm_mon = tm->tm_mon;
  285.     t->tm_year = tm->tm_year;
  286.     return p;
  287.   }
  288.   p++;
  289.   t->tm_mon = strtol (p, &p, 0) - 1;
  290.   if (t->tm_mon < 0 || t->tm_mon > 11)
  291.   {
  292.     snprintf (err, errlen, "Invalid month: %s", p);
  293.     return NULL;
  294.   }
  295.   if (*p != '/')
  296.   {
  297.     t->tm_year = tm->tm_year;
  298.     return p;
  299.   }
  300.   p++;
  301.   t->tm_year = strtol (p, &p, 0);
  302.   if (t->tm_year > 1900)
  303.     t->tm_year -= 1900;
  304.   return p;
  305. }
  306.  
  307. /* returns local - UTC in secodnds */
  308. static int mutt_local_tz (void)
  309. {
  310.   time_t tz, now = time (NULL);
  311.   int yday;
  312.   struct tm *tm;
  313.  
  314.   tm = localtime (&now);
  315.   tz = tm->tm_hour * 3600 + tm->tm_min * 60;
  316.   yday = tm->tm_yday;
  317.  
  318.   tm = gmtime (&now);
  319.   tz -= tm->tm_hour * 3600 + tm->tm_min * 60;
  320.   yday -= tm->tm_yday;
  321.  
  322.   /* if UTC is on a different day from local, add 24 hours to get the offset */
  323.   tz += 86400 * yday;
  324.  
  325.   return (tz);
  326. }
  327.  
  328. static const char *
  329. eat_date (pattern_t *pat, const char *s, char *err, size_t errlen)
  330. {
  331.   struct tm min;
  332.   struct tm max;
  333.   time_t tz;
  334.  
  335.   memset (&min, 0, sizeof (min));
  336.   memset (&max, 0, sizeof (max));
  337.  
  338.   /* Arbitrary year in the future.  Don't set this too high
  339.    * or mutt_mktime() returns something larger than will
  340.    * fit in a time_t on some systems
  341.    */
  342.   max.tm_year = 130;
  343.   max.tm_mon = 11;
  344.   max.tm_mday = 31;
  345.   max.tm_hour = 23;
  346.   max.tm_min = 59;
  347.   max.tm_sec = 59;
  348.  
  349.   if (*s != '-')
  350.   {
  351.     /* mininum date specified */
  352.     if ((s = getDate (s, &min, err, errlen)) == NULL)
  353.       return NULL;
  354.   }
  355.  
  356.   if (*s && *s == '-')
  357.   {
  358.     /* max date */
  359.     s++; /* skip the `-' */
  360.     if (*s)
  361.       if ((s = getDate (s, &max, err, errlen)) == NULL)
  362.     return NULL;
  363.   }
  364.   else
  365.   {
  366.     /* search for messages on a specific day */
  367.     max.tm_year = min.tm_year;
  368.     max.tm_mon = min.tm_mon;
  369.     max.tm_mday = min.tm_mday;
  370.   }
  371.  
  372.   tz = mutt_local_tz ();
  373.   pat-